
#ifndef __XB_DEV_PCI_H__
#define __XB_DEV_PCI_H__

/* ------------------------------------------------------------------------- */

#define PCI_CONFIG_ADDR						0x0cf8
#define PCI_CONFIG_ADDR_SIZE				4
#define PCI_CONFIG_DATA						0x0cfc
#define PCI_CONFIG_DATA_SIZE				4

#define PCI_CONFIG_SIZE						256
#define PCI_CONFIG_HEADER_SIZE				64
#define PCI_CONFIG_BODY_SIZE				(PCI_CONFIG_SIZE - PCI_CONFIG_HEADER_SIZE)

/* base address register for I/O */
#define PCI_BASE_ADDR_IO					0x00000001		/* I/O mapping */

/* base address register for memory */
#define PCI_BASE_ADDR_MEM					0x00000000		/* memory mapping */
#define PCI_BASE_ADDR_MEM_PREFETCH			0x00000008		/* prefetchable */
#define PCI_BASE_ADDR_MEM_TYPE				0x00000006		/* type */

enum {
	PCI_DEV_HOST,
	PCI_DEV_MEM,
	PCI_DEV_ISA,
	PCI_DEV_SMBUS,
	PCI_DEV_USB1,
	PCI_DEV_USB2,
	PCI_DEV_NET,
	PCI_DEV_AUD,
	PCI_DEV_ACI,
	PCI_DEV_IDE,
	PCI_DEV_AGP,
	PCI_DEV_VGA,
	PCI_DEV_NUM,
};

/* ------------------------------------------------------------------------- */

typedef struct {
	uint16 vendor;						/* vendor ID */
	uint16 device;						/* device ID */
	uint16 command;						/* command */
	uint16 status;						/* status */
	uint32 rev_class;					/* class code & revision ID */
	uint8 cache_size;					/* cacheline size */
	uint8 latency;						/* latency timer */
	uint8 header_type;					/* header type */
	uint8 bist;							/* BIST */
	union {
		struct {
			uint32 base_addr[6];		/* base address register 0~5 */
			uint32 cis_ptr;				/* cardbus CIS pointer */
			uint16 sub_vendor;			/* subsystem vendor ID */
			uint16 subsystem;			/* subsystem ID */
			uint32 exp_rom_base;		/* expansion ROM base address */
			uint32 reserved[2];			/* reserved */
			uint8 intr_line;			/* interrupt line */
			uint8 intr_pin;				/* interrupt pin */
			uint8 min_gnt;				/* min gnt */
			uint8 max_lat;				/* max lat */
		} type0;						/* for general device */
		struct {
			uint32 base_addr[2];		/* base address register 0~1 */
			uint8 primary_bus;
			uint8 secondary_bus;
			uint8 subordinate_bus;
			uint8 latency2;
			uint8 io_base;
			uint8 io_limit;
			uint16 status2;
			uint16 mem_base;
			uint16 mem_limit;
			uint16 pm_base;
			uint16 pm_limit;
			uint32 pm_base_high;
			uint32 pm_limit_high;
			uint16 io_base_high;
			uint16 io_limit_high;
			uint32 cap_ptr;
			uint32 exp_rom_base;
			uint8 intr_line;
			uint8 intr_pin;
			uint16 bridge_con;
		} type1;						/* for PCI-to-PCI bridge device */
	} hdr;
	uint32 data[48];
} pci_conf_t;

typedef struct {
#ifndef NDEBUG
	char name[10];
#endif
	pci_conf_t conf;
	void (fastcall * config)(uint8 reg, uint32 data, uint32 mask);
	size_t (fastcall * map_size)(uint map);
	size_t (fastcall * read_map)(uint map, uint32 addr, void *data, size_t size);
	size_t (fastcall * write_map)(uint map, uint32 addr, const void *data, size_t size);
} pci_dev_t;

/* ------------------------------------------------------------------------- */

capi void fastcall pci_init(void);

capi uint32 fastcall pci_get_config_addr(void);
capi void fastcall pci_set_config_addr(uint32 addr, uint32 mask);

capi uint32 fastcall pci_get_config_data(void);
capi void fastcall pci_set_config_data(uint32 data, uint32 mask);

capi size_t fastcall pci_io_mapping_read(uint16 port, void *buf, size_t size);
capi size_t fastcall pci_io_mapping_write(uint16 port, const void *buf, size_t size);

capi size_t fastcall pci_mem_mapping_read(uint32 addr, void *buf, size_t size);
capi size_t fastcall pci_mem_mapping_write(uint32 addr, const void *buf, size_t size);

capi void fastcall pci_config_header(const pci_dev_t *dev, uint8 reg, uint32 data, uint32 mask);

capi pci_dev_t *get_host_device(void);
capi pci_dev_t *get_mem_device(void);
capi pci_dev_t *get_isa_device(void);
capi pci_dev_t *get_smbus_device(void);
capi pci_dev_t *get_usb1_device(void);
capi pci_dev_t *get_usb2_device(void);
capi pci_dev_t *get_net_device(void);
capi pci_dev_t *get_aud_device(void);
capi pci_dev_t *get_aci_device(void);
capi pci_dev_t *get_ide_device(void);
capi pci_dev_t *get_agp_device(void);
capi pci_dev_t *get_vga_device(void);

/* ------------------------------------------------------------------------- */

#endif
